Translated by visionNoob, KNU https://github.com/insurgent92/CS231N_17_KOR_SUB
잘 들리시나요? 좋습니다. 잠시 지연이 있었습니다.
잠시 기술적인 문제가 있었습니다.
오늘은 10강입니다. Recurrent Neural Networks(RNN)에 대해 배워보겠습니다.
그 전에 공지사항을 전달하겠습니다.
현재 과제1을 채점 중에 있습니다.
최종 성적이 아마도 오늘 발표될 예정입니다. 과제2 deadline 전에는 과제1 성적이 나왔으면 좋겠네요
과제2의 제출기한은 금일 11:59 p.m. 까지입니다.
과제 2를 다 마치신 분 있으신가요? 절반정도 되는군요
제가 예전에 과제2는 상당히 오래걸릴 수 있으니 미리 시작하는 것이 좋다고 말씀드렸습니다.
late dates가 남아있길 바랍니다.
화요일 수업시간에는 중간고사가 있습니다.
아마 강의실이 비좁아서 모두 시험을 치룰 수 없을 것입니다.
따라서 다른 강의실들도 함께 빌려서 진행할 예정입니다.
향후 세부사항은 다시한번 공지하겠습니다.
또 한가지 공지사항이 있습니다.
현재 Train Game 이라는 사이트를 개설하고있습니다. Train Game은 웹 브라우저 기반이며
여러분 누구나 접속해서 딥러닝 모델을 학습시키고 학습 도중 하이퍼파라미터를 조정하실 수 있습니다.
앞서 강의들에서 배웠던 다양한 하이퍼파라미터들을 손으로 직접 만져볼 수 있는 아주 좋은 툴입니다.
Train Game를 무조건 하실 필요는 없습니다. 하지만, Train Game는 실제로 다양한 데이터를 다뤄보며
데이터 타입에 따라 하이퍼파라미터가 어떤 영향을 미치는지에 직관을 얻을 수 있는 아주 좋은 기회가 될것입니다.
현재 몇 가지 버그를 수정하고 있습니다. 조만간 여러분에게 사용법과 함께 공개하도록 하겠습니다.
다시한번 말씀드리지만, 필수는 아닙니다. 하지만 해보시면 도움이 많이 될 것입니다.
Train Game을 써보신 분들에게는 Extra credit을 지급할 예정입니다.
아무튼 버그만 다 잡으면 다시 한번 공지드리겠습니다.
지난 강의 복습을 해봅시다. CNN 아키텍쳐들을 배웠습니다.
ImageNet Classification Challenge를 중심으로 연대순 우승자들을 알아봤습니다.
2012년에는 AlexNet이 있었습니다. 9-layer CNN인데, 아주 잘 동작했습니다.
AlexNet이 Computer Vision의 진화를 촉발시켰으며 딥러닝 시대의 서막을 열었습니다.
2014년으로 넘어가봅시다. 이전의 모델들보다 훨씬 더 깊어진 두 모델이 있었습니다. VGG와 GoogLeNet 입니다.
VGGNet은 16/19 레이어를, GoogLeNet은 22 레이어를 가진 모델이었습니다.
2014년 모델들에서 흥미로운 점은 2014년에는 Batch normalization 이 발명되기 이전이라는 점입니다.
Batch Norm이 없던 시절이라서 레이어가 깊을 모델을 학습시키는 일은 상당히 어려웠습습니다.
이 두 모델은 깊은 모델을 수렴시키기 위해서 각종 테크닉(hackery)을 써야했습니다.
가령 VGGNet는 16/19 레이어가 있습니다.
하지만 처음에는 11레이어 모델을 학습시켰습니다. 11 레이어가 모델이 잘 수렴하는 한계였습니다.
그리고 나서 11레이어 중간에 레이어를 무작위로 추가해서 VGG-16, VGG-19 를 학습시킨 것이죠
이렇게, Bath norm이 없던 2014년에는 학습 자체가 상당히 어려운 문제였습니다.
유사한 사례로 GoogLeNet의 경우에는 auxiliary classifiers를 도입했습니다.
auxiliary classifiers는 classification 성능을 올리기 위해서 도입된 것이 아닙니다.
단지 네트워크의 초기 레이어에 gradient를 직접 흘려보내기 위한 수단이었습니다.
GoogLeNet은 Batch Norm 이전에 이런 테크닉을 사용했습니다.
하지만 Batch Norm이 있다면 굳이 이런 식의 테크닉은 더이상 필요하지 않습니다.
2015년에는 ResNet이라는 아주 멋드러진 모델이 있었습니다.
ResNet은 shortcut connection과 residual block이 도입된 모델입니다.
ResNet에서는 레이어의 출력은 입력 + residual block의 출력 입니다.
아주 흥미로운 구조입니다. 이 구조는 두 가지 아주 좋은 속성을 지니고 있습니다.
하나는, 우선 residual block의 가중치가 0이면 이 block은 indentity mapping 을 합니다.
이 속성은, 모델이 '필요없는 레이어" 를 사용하지 않도록 학습하는데 아주 유용합니다.
그리고 ResNet의 관점에서 L2 Regularization을 해석해 볼 수도 있습니다.
레이어에 L2 Regularization을 추가시키면 L2는 모든 파라미터가 0이 되도록 노력할 것입니다.
사실 기본적인 CNN 아키텍쳐의 관점에서보면 모든 파라미터가 0이면 이상합니다.
하지만 ResNet의 관점에서는 파라미터를 0으로 만드려는 속성은 모델이 불필요한 레이어를 사용하지 않도록 해줄 수 있습니다.
파라미터들을 계속 0으로 보내면 residual block이 identity가 되기 떄문이죠.
ResNet의 또 한가지 특성은 backward pass 에서의 gradient flow와 관련있습니다.
"Addition gates (+)" 가 backward pass에 어떤 영향을 미칠지 생각해보면
Upstream gradient 가 "Addition gate" 를 만나면 두 갈래로 나눠지게 됩니다.
Upstream gradient가 오면 convolution block 으로도 흘러들어가지만
residual connection 덕분에 현재 레이어를 생략하고 직접 이전 레이어로 흘러갈 수도 있습니다.
Residual blocks을 수백 레이어 쌓아올린 네트워크가 있다고 해봅시다.
Residual connection은 gradient를 위한 일종의 고속도로 역할을 합니다. gradient를 원활하게 전달하기 위해서죠
이런 특성으로 학습을 더 쉽고 빠르게 할 수 있습니다.
그리고 이런 특성은 모델이 엄청 깊더라도 잘 수렴할 수 있도록 도와줍니다.
모델의 gradient flow를 잘 다루는 것은 Machine learning 전 분야에 걸쳐서도 아주 중요합니다.
RNN에서도 아주 중요하죠. 따라서 gradient flow는 오늘 강의의 후반부에 다시한번 다루겠습니다.
지난 시간에 DensNet, FractalNet 과 같은 이색적인 CNN 아키텍쳐도 살펴보았습니다.
이 모델들은 gradient flow의 관점에서 아주 잘 해석해 볼 수 있습니다.
DenseNet이나 FractalNet 같은 모델들은 모델 내부에 additional shortcut (identity)를 추가합니다.
이 모델들은 Loss와 각 Layer를 직접 연결하기 때문에 backward pass가 아주 수월합니다.
CNN 아키텍쳐에서 Gradient Flow를 잘 다루려는 시도는 최근 몇 년간 아주 활발하게 이루어졌습니다.
앞으로도 신기한 아카텍쳐들이 많이 나올 것 같습니다.
지난 강의에서 보셨던 그래프입니다. 모델 별 연산량, 크기 등을 비교해 보았습니다.
이 그래프를 유심히 살펴보면 아주 재미있는 속성이 있습니다.
AlexNet와 VGGNet는 파라미터가 엄청 많습니다.
사실 파라미터가 많은 이유는 전적으로 FC-layer 때문입니다.
가령 AlexNet의 경우에는 대략 64M 개의 파라미터가 있습니다.
AlexNet의 FC-Layer를 살펴봅시다. FC-Layers의 입력은 마지막 Conv output 6 x 6 x 256 입니다.
이 값(256 x 6 x 6) 들이 4096 개의 FC-layer 노드와 연결됩니다.
이 부분의 가중치 매트릭스는 엄청나게 큽니다.
매트릭스의 크기는 6x6x256x4096 이 되겠죠
이 레이어 하나에만 38m개의 파라미터가 있습니다.
AlexNet의 전체 파라미터 중 절반 이상이 FC-Layer에 집중되어 있습니다.
AlexNet의 FC-Layer 의 파라미터 갯수를 다 더해보면 FC-Layer에서만 62M 가량의 파라미터가 있다는 것을 알 수 있습니다.
GoogLeNet 이나 ResNet 같은 아키텍쳐들은 FC-Layer를 상당부분 걷어냈습니다.
FC-Layer를 Global Average Pooling (GAP) 으로 대체시킵니다.
GAP를 사용하게 되면서 파라미터 갯수를 상당히 감소시켰습니다.
지금까지는 CNN 아키텍쳐를 복습해보았습니다.
이제부터는 Recurrent Neural Network에 대해서 배워보도록 하겠습니다.
지금까지 배운 아키텍쳐들은(Vanilla Neural Network) 다음과 같은 모양이하고 할 수 있습니다.
네트워크는 이미지 또는 벡터를 입력으로 받습니다.
입력 하나가 Hidden layer를 거쳐서 하나의 출력을 내보냅니다.
Classification 문제라면 카테고리가 되겠군요
하지만 Machine Learning의 관점에서 생각해보면 모델이 다양한 입력을 처리할 수 있도록 유연해질 필요가 있습니다.
그런 관점에서 RNN은 네트워크가 다양한 입/출력을 다룰 수 있는 여지를 제공해줍니다.
RNN 구조를 이용할 때, 가령 "one to many" 모델은
입력은 이미지와 같은 "단일 입력" 이지만 출력은 caption 과 같은 "가변 출력" 입니다.
caption에 따라서 단어의 수가 천차 만별이겠죠 따라서 출력은 가변 출력입니다.
"many to one" 모델도 있습니다.
이제는 입력이 "가변 입력" 입니다. 가령 문장이 될 수 있겠군요
그리고 이 문장의 "감정"을 분류하는 것입니다. 부정적/긍적적인 문장인지를 구별하는 것이죠
그리고 Computer Vision Task의 경우에는, 가령 입력이 비디오라고 해봅시다. 비디오에 따라 전체 프레임 수가 다양합니다.
전체 비디오를 읽으려면 가변 길이의 입력을 받아야 합니다.
비디오를 입력으로 받아서, 비디오에 나타나는 activity 또는 action을 분류하는 문제를 생각해봅시다.
이 경우에는 입/출력 모두 가변이어야 합니다.
또는 Machine translation의 예를 볼 수도 있습니다. 입력은 English sentence 입니다. 가변 입력이죠
그리고 출력은 번역 결과인 "Fench sentence" 입니다. 출력 또한 가변 출력인 것입니다.
그리고 English Sentence의 길이는 변역된 French Sentence의 길이와 다를 것입니다.
이 경우에는 가변 입/출력이 가능한 모델이 필요합니다.
마지막으로, 입력은 비디오와 같은 가변 입력이고 각 프레임마다 출력 값이 나와야 하는 상황을 생각해 볼 수 있습니다.
가령 비디오가 입력이고 매 프레임마다 classification을 해야 하는 상황일 수 있습니다.
Recurrent Neural Networks는 가변 길이의 데이터를 다루기 위해 필요한 일반적인 방법(paradigm) 입니다.
RNN은 앞서 말씀드린 다양한 상황들을 모델이 잘 처리할 수 있도록 줍니다.
그리고 고정 길이의 입/출력이 필요한 상황에서도 RNN은 상당히 중요합니다. 여전히 유용하죠.
입/출력은 고정이지만 sequential processing가 요구되는 경우입니다.
가령 여기 이미지가 있습니다. 고정 입력이죠 그리고 이미지의 숫자가 몇 인지 분류하는 문제입니다.
입력 이미지의 정답을 feed forward pass 한 번만 가지고 결정하는 것이 아니라
이 네트워크는 이미지의 여러 부분은 조금씩 살펴봅니다.
이미지를 살펴 본 후에 숫자가 몇 인지를 최종적으로 판단합니다.
이 예제 처럼 입/출력이 고정된 길이라고 해도 "가변 과정(processing)" 인 경우에 RNN은 상당이 유용합니다.
제가 상당히 좋아하는 논문입니다. 동일한 방법으로 "이미지를 생성" 을 제안하기도 합니다.
자 이제는 모델은 Train time에서 본 이미지들을 바탕으로 새로운 이미지를 생성해 냅니다.
이를 위해 RNN을 이용할 수 있습니다. 순차적으로 전체 출력의 일부분씩 생성해 내는 것입니다.
이 경우에도 전체 출력은 고정된 길이지만, RNN을 이용해서 일부분씩 순차적으로 처리할 수 있습니다.
RNN을 이런 경우에도 사용될 수 있는 것이죠.
RNN을 활용할 수 있는 다양한 예시들을 살펴보았습니다. 그렇다면 도대체 어떻게 동작하는 것일까요?
일반적으로 RNN은 작은 "Recurrent Core Cell" 을 가지고 있습니다.
입력 x가 RNN으로 들어갑니다. RNN에는 내부에 "hidden state" 를 가지고있습니다.
"hidden state"는 RNN이 새로운 입력을 불러들일 때마다 매번 업데이트됩니다.
"hidden state"는 모델에 feed back되고 이후에 또 다시 새로운 입력 x가 들어옵니다.
RNN이 매 단계마다 값을 출력하는 경우를 생각해 봅시다.
그러면 이런 식으로 진행이 됩니다. 1. RNN이 입력을 받습니다.
2. "hidden state"를 업데이트합니다. 3. 출력 값을 내보냅니다.
그렇다면 RNN 구조를 수식적으로 표현하면 어떨까요?
오른쪽 그림의 초록색 RNN block은 "재귀적인 관계"를 연산할 수 있도록 설계됩니다. "함수 f" 로 말이죠
파라미터 W를 가진 함수 f가 있습니다.
함수 f는 "이전 상태의 hidden state인 h_t-1" 과 "현재 상태의 입력인 x_t" 를 입력으로 받습니다.
그리고 h_t를 출력합니다. h_t는 "다음 상태의 hidden state" 입니다.(updated hidden state)
그리고 다음 단계(state)에서는 h_t와 x_t+1가 입력이 됩니다.
RNN에서 출력 값(y)을 가지려면 h_t 를 입력으로 하는 FC-Layer을 추가해야 합니다.
FC-Layer는 매번 업데이트되는 Hidden state(h_t)를 기반으로 출력 값을 결정합니다.
중요한 사실은 함수 f와 파라미터 W는 매 스텝 동일하다는 것입니다.
자, RNN을 가장 간단하게 수식적으로 나타내려면 단순한(vanilla) RNN부터 시작하는게 좋겠군요
지금 보이는 수식은 앞서 있던 수식과 동일합니다.
"이전 hidden state"와 "현재 입력"을 받아서 "다음 hidden state"를 출력합니다.
이를 수식적으로 가장 간단하게 표현해보면, 가중치 행렬 W_xh 와 입력 x_t의 곱으로 나타낼 수 있습니다.
또한 가중치 행렬 W_hh도 있습니다. "이전 hidden state"와 곱해지는 값입니다.
이렇게 두 입력(h,x) 에 대한 행렬 곱 연산이 있고 두 결과 값을 더해줍니다.
그리고 System에 non-linearity를 구현하기 위해 tanh를 적용합니다.
여러분 중에 왜 다른 non-linearity가 아닌 tanh를 쓰는지 궁금하신 분들도 계실 것입니다.
지난 강의 동안에는 tanh가 안좋다고만 배웠는데 말이죠
tanh와 관련된 문제는 lstm 배울 때 다시한번 다뤄드리도록 하겠습니다.
자 이제 우리는 매 스텝마다 출력 y를 얻고 싶습니다.
이를 위해서는 "hidden state"인 h_t 를 새로운 가중치 행렬 W_hy 와 곱해줍니다.
가령 매 스텝에 출력 y는 class score가 될 수 있을 것입니다.
Recurrent Neural Network는 크게 두 가지 방법으로 해석해 볼 수 있습니다.
하나는 RNN이 hidden state를 가지며 이를 "재귀적으로" feed back 한다는 점입니다.
RNN을 사실 이런 식으로 표현하면 많이 헷갈립니다. Multiple time steps을 unrolling 해서 보면 좋습니다.
Unrolling을 하면 hidden states, 입/출력, 가중치 행렬들 간의 관계를 조금 더 명확히 이해할 수 있습니다.
첫 step에서는 initial hidden state인 h_0 가 있습니다.
대부분의 경우 h_0 는 0으로 초기화시킵니다. 그리고 입력 x_t가 있습니다.
h_0와 x_1 이 함수 f_w의 입력으로 들어갑니다.
f_w(h_0, x_1) 의 출력은 h_1 입니다. 이 과정이 반복됩니다. 이번에는 x_2 이 다음 입력으로 들어옵니다.
f_w(h_1, x_2) 의 출력은 h_2가 됩니다.
이 과정을 반복하면서 가변 입력 x_t 를 받습니다.
이제는 조금 더 구체적인 이해를 위해서 행렬 W를 그려넣어 봅시다.
여기에서 주목할 점은 "동일한 가중치 행렬 W"가 매번 사용된다는 점입니다.
매번 h와 x는 달라지지만 W는 매번 동일합니다.
앞서 Computational graph에서 동일한 node를 여러번 사용할 때 back prop gradient flow이 어떨지 배웠습니다.
backward pass 시 dLoss/dW 를 계산하려면 행렬 W의 gradient를 전부 더해줬습니다.
따라서 이 RNN 모델의 backprop을 위한 행렬 W의 그레디언트를 구하려면
각 스텝에서의 W에 대한 그레디언트를 전부 계산한 뒤에 이 값들을 모두 더해주면 됩니다.
Computational graph에 y_t도 넣어볼 수 있습니다.
RNN의 출력 값 h_t가 또 다른 네트워크의 입력으로 들어가서 y_t를 만들어 냅니다.
가량 y_t는 매 스텝의 class score가 될 수 있겠죠
RNN의 Loss도 한번 살펴봅시다.
각 시퀀스마다 Ground truth label이 있다고 해봅시다. 그러면 각 스텝마다 개별적으로 y_t에 대한 Loss를 계산할 수 있습니다.
여기에서 Loss는 가령 softmax loss가 될 수 있겠죠
RNN의 최종 Loss는 각 개별 loss들의 합입니다.
각 단계에서 Loss가 발생하면 전부 더하여 최종 네트워크 Loss를 계산합니다.
이 네트워크의 Backprop을 생각해보면 모델을 학습시키려면 dLoss/dW를 구해야 합니다.
Loss flowing은 각 스텝에서 이루어집니다.
이 경우에는 각 스텝마다 가중치 W에 대한 local gradient를 계산할 수 있습니다.
이렇게 개별로 계산된 local gradient를 최종 gradient에 더합니다.
그렇다면 "many to one" 이라면 어떨까요? 가령 감정분석(sentiment analysis) 처럼 말입니다.
이 경우에는 네트워크의 최종 hidden state에서만 결과 값이 나올 것입니다.
최종 hidden state가 전체 시퀀스의 내용에 대한 일종의 요약으로 볼 수 있기 떄문입니다.
그렇다면 "one to many" 의 경우에는 어떨까요?
"고정 입력" 을 받지만 "가변 출력"인 네트워크입니다.
이 경우에는 대게 고정 입력은 모델의 initial hidden state를 초기화시키는 용도로 사용합니다.
그리고 RNN은 모든 스텝에서 출력 값을 가집니다.
이렇게 가변 출력을 가지는 경우에도 이렇게 그래프를 Unroll 해 볼 수 있습니다.
"sequence to sequent" 모델에 대해서 알아보겠습니다. 가령 machine tranlation 에 사용할 수 있는 모델입니다.
"가변 입력" 과 "가변 출력" 을 가지는 모델입니다.
우리는 이 모델을 "many to one" 모델과 "one to many" 모델의 결합으로 볼 수 있습니다.
두 개의 스테이지로 구성되는 것이죠. encoder와 decoder 구조입니다.
encoder는 가변 입력을 받습니다. 가령 English sentence가 될 수 있겠죠
그리고 encoder의 final hidden state 를 통해 전체 sentence를 요약합니다.
Encoder 에서는 "many to one" 을 수행합니다. "가변 입력"을 하나의 벡터로 요약합니다.
반면 Decoder는 "one to many"를 수행합니다. 입력은 앞서 요약한 "하나의 벡터" 입니다.
그리고 decoder는 "가변 출력"을 내뱉습니다. 가령 다른 언어로 변역된 문장이 될 수 있겠죠
"가변 출력" 은 매 스텝 적절한 단어를 내뱉습니다.
그림처럼 전체 Computational graph를 풀어서 전체 학습과정을 해석해보면
Output sentence의 각 losses를 합해서 Backprob 을 진행합니다.
조금 더 구체적인 예를 살펴보겠습니다. 대게는 RNN 은 Language modeling에서 자주 사용합니다.
Language modeling 문제에서 하고싶은 것은 바로 "어떻게 자연어(natural lang)을 만들어낼지 입니다.
가령 문자(characters) 를 내뱉는 모델이라면 매 스텝 어떻게 문자를 생성해 낼지를 풀어야 합니다.
단어(word) 를 내뱉는 모델이라면 매 스텝 어떻게 단어를 생성해 낼 지를 풀어야겠죠
우선은 간단한 예제를 위해서 character level language model 을 살펴보겠습니다.
네트워크는 문자열 시퀀스를 읽어드리고, 현재 문맥에서 다음 문자를 예측해야 합니다.
이번 예제에서는 간단하게 단어가 [h,e,l,o] 만 있습니다. 그리고 학습시킬 문장은 "h, e, l, l, o" 입니다.
Train time에서는 training sequence("hello") 의 각 단어들을 입력으로 넣어줘야 합니다.
"hello" 가 RNN의 x_t입니다.
우선 입력은 한 글자(letter)씩 입니다. 네트워크도 적절한 글자들을 출력해야 합니다.
일반적으로 입력을 넣어주는 방법이 있습니다. 우선 vocabulary는 총 네 가지입니다.[h, e, l, o]
각 글자는 하나의 벡터로 표현할 수 있습니다. 이 벡터는 1이 하나 있고 나머지는 0인 벡터입니다.
벡터에서 해당 글자 위치만 1로 표시합니다.
이 단순한 예제에서는 글자가 h, e, l, o 뿐입니다. 따라서 4-d 벡터로 표현할 수 있습니다.
가령 h를 벡터로 표현하는 경우([1,0,0,0]) h에 해당하는 자리만 1이고 나머지는 0입니다.
이런 식으로 다은 문자들도 벡터로 표현할 수 있습니다.
Forward pass에서 네트워크가 어떻게 동작하는지 살펴봅시다. 우선 첫 스텝에서는, 입력 문자 'h' 가 들어옵니다.
첫 번째 RNN cell로는 'h' 가 들어갑니다. 그러면 네트워크는 y_t를 출력합니다.
y_t는 어떤 문자가 'h' 다음에 나올 것 같은지를 예측한 값입니다.
이 예제에서는 'h' 다음에는 'e' 를 예측해야 정답입니다.
하지만 현재 이 모델은 다음에 나올 글자가 'o' 라고 예측하고 있습니다.
잘못 예측한 경우입니다. softmax loss가 이 예측이 얼마나 형편없는지 알려줄 것입니다.
다음 스텝에서는 두 번째 단어 'e' 가 입력으로 들어갑니다. 이런 과정이 반복됩니다.
우선 'e' 벡터입니다. 그리고 "이전 hidden state"와 함께 "새로운 hidden state" 를 만들어내죠
이제는 두번째 hidden state를 이용해서 적절한 값을 예측해야 합니다.
'hello' 를 예측해야 하므로 'e' 가 입력이라면 'l' 을 예측해야합니다.
이 경우 'l' 의 예측 치가 상당히 낮기 때문에 Loss가 높습니다.
이 과정을 반복합니다. 모델을 다양한 문장으로 학습시킨다면
결국 모델은 이전 문장의 문맥을 참고해서 다음 문자가 무엇일지를 학습해야 할 것입니다.
그렇다면 이 모델의 Test time은 어떨까요?
이렇게 학습시킨 모델을 활용할 수 있는 방법들 중 하나는 Model로부터 Sampling 하는 것입니다.
다시말해, Train time에 모델이 봤을 법한 문장을 모델 스스로 생성해 내는 것입니다.
우선 모델에게 문장의 첫 글자만 줍니다. 이 경우에는 'h' 가 되겠군요
RNN 의 첫 스텝의 입력은 'h'가 될 것입니다.
'h'가 주어지면 모든 문자(h,e,l,o) 에 대한 스코어를 얻을 수 있습니다(output layer)
Test time에서는 이 스코어를 "sampling"(다음 글자 선택)에 이용 합니다.
스코어를 확률분포로 표현하기 위해서 sofrmax 함수를 사용할 수 있습니다.
문장의 두 번째 글자를 선택하기 위해서 이 확률분포를 이용합니다.
이 경우에 'e'가 뽑힐 확률(13%)이 엄청 낮았음에도 아주 운좋게 'e'가 샘플링되었습니다.
이제는 확률 분포에서 운좋게 뽑힌 'e' 를 다음 스텝의 네트워크 입력으로 넣어 줄 것입니다.
'e' 를 다시 벡터[0,1,0,0]로 만들어주고 다음 입력으로 넣어주면 네트워크는 두번째 출력을 만들어 냅니다.
이 학습된 모델만 가지고 새로운 문장을 만들어내기 위해 이 과정을 반복합니다.
전체 문장을 만들어내기 위해 타임 스텝마다 확률 분포에서 문자를 하나씩 뽑아냅니다.
질문 있나요?
질문은 "가장 높은 스코어를 선택하면 그만인데 왜 굳이 확률분포에서 샘플링하는지" 입니다.
이 예제의 경우에는 가장 스코어가 높은 값만 사용하면 올바른 결과를 낼 수 없었습니다. (e 스코어가 낮았음)
따라서 확률분포에서 샘플링을 했기 때문에 hello를 잘 만들 수 있었습니다.
실제로는 두 경우 모두 사용할 수 있습니다. (확률 분포에서 샘플링 or 그냥 가장 높은 값)
어떤 경우에는 argmax probability만 사용할 수 있습니다. (가장 높은 값을 취함) 더 안정적인 방법일 수 있습니다.
하지만 확률 분포에서 샘플링하는 방법을 사용하면 일반적으로는 모델에서의 다양성을 얻을 수 있습니다.
만약 항상 같은 접두사(예제에서 h)라던지, 이미지라면 같은 사진이라던지를 모델 입력으로 주면
argmax을 하지 않고 샘플링을 하게되면 그럴듯한 다양한 문장을 출력할 수 있게 됩니다.
첫 스텝에서 어떤 값이 샘플링되는지에 따라서 출력이 다양해 질 수 있는 것입니다.
샘플링 하는 방법은 다양한 출력을 얻을 수 있다는 관점에서 좋은 방법이 될 수 있습니다.
다른 질문 있나요?
[학생이 질문]
질문은 "Test time에 sofrmax vector를 one hot vector 대신에 넣어줄 수 있는지" 입니다.
두 가지 문제가 발생할 수 있습니다. 첫 째는 그렇게 되면 입력이 Train time에서 본 입력과 달라집니다.
모델에게 Train time에서 보지 못한 입력값을 주게되면 대게는 모델이 아무것도 하지 못합니다.
두 번째 문제는 실제로는 vocabularies가 아주 크다는 것입니다.
예제에서는 voca가 4개 뿐이 없어서 크게 문제될 것이 없겠지만
한 스텝마다 단어(word)를 생성하는 모델이라고 보면 voca 안에는 이세상의 모든 영어단어가 들어가야합니다.
voca는 수만개 이상의 요소를 가지게 되겠죠
실제론 one hot vector를 sparse vector operation 으로 처리합니다. (dense vector가 아닌)
10,000dim softmax vector를 연산해야 한다면 연산량이 어마어마 할 것입니다.
Test time에서도 one hot을 사용하는 이유입니다.
이런 모델의 경우 시퀀스 스텝마다 출력값이 존재합니다.
이 출력값들의 Loss를 계산해 final loss를 얻는데 이를 "backpropagation through time" 라고 합니다.
이 경우, forward pass의 경우에는 전체 시퀀스가 끝날 때 까지 출력값이 생성됩니다.
반대로 backward pass에서도 전체 시퀀스를 가지고 Loss를 계산해야 합니다.
하지만 이 경우 시퀀스가 아주 긴 경우에는 문제가 될 소지가 있습니다.
가령 Wikipedia 전체 문서로 모델을 학습시킨다고 해봅시다.
이 경우 학습이 정말 느릴 것입니다. gradient를 계산하려면 Wikipedia 전체 문서를 다 거쳐야 할 것입니다.
Wikipedia 문서 전체에 대한 gradient를 계산하고 나면 gradient update가 1회 수행됩니다.
이 과정은 아주 느릴 것입니다. 모델이 수렴될리 없겠죠. 메모리 사용량도 어마어마할 것입니다.
실제로는 "truncated backpropagation" 를 통해서 backprob 을 근사시키는 기법을 사용합니다.
이 방법의 아이디어는 비록 입력 스퀀스가 엄청나게 길어서 무한대라고 할지라도
Train time에 한 스텝을 일정 단위로 자릅니다. 대략 100 정도로 말이죠
100 스텝만 forward pass를 하고 이 서브스퀀스의 Loss를 계산합니다. 그리고 gradient step을 진행하는 것이죠.
이 과정을 반복합니다. 다만 이전 batch에서 계산한 hidden states는 계속 유지합니다.
다음 Batch의 forward pass를 계산할 때는 이전 hidden state를 이용합니다.
그리고 gradient step은 현재 Batch에서만 진행합니다.
이 방법을 "truncated backpropagation through time" 이라고 합니다.
이 과정을 반복합니다. 이전 batch에서 hidden states를 가져와서 foward pass를 수행하고
backprob은 현재 배치만큼만 진행합니다.
이 방법은 Stocastic gradient descent의 시퀀스 데이터 버전이라고 볼 수 있습니다.
지난 시간이 Data Sets이 엄청 큰 경우 어떻게 학습시켜야 하는지 배웠습니다.
Large datasets에서는 전체 데이터로 gradients를 계산하기에는 계산량이 너무 컸습니다.
그래서 대신에 mini batch를 사용해서 small samples만 가지고 계산했습니다.
그리고 mini batch만을 이용해서 gradient를 계산했습니다. 가령 Image classification에서 그랬었죠
질문있나요?
질문은 "RNN이 Markov Assumption 을 따르는지" 입니다.
그렇지 않습니다. 왜냐하면 RNN은 이전 hidden state를 계속해서 앞으로 가져가기 때문입니다.(영원히)
마르코 비아 가정을하고있다. 숨겨진 상태를 조건으로,
그러나 숨겨진 상태가 우리가 필요로하는 모든 것입니다. 미래를 예언하기 시퀀스의
하지만 그 가정은 일종의 건축입니다. 재발 성 신경 네트워크 공식 출발점에서.
그리고 그것은 정말로 특별하지 않습니다. 시간을 통한 전파를 역전 시키십시오.
Truncated backprop은 very large sequence data의 gradient를 근사시키는 방법입니다.
RNN을 구현하려면 코드도 엄청 복잡하고 어려울 것 같아 보이지만 사실은 그렇지 않습니다. 엄청 간결합니다.
Andrej가 min-char-rnn 이라는 코드를 만들어놨습니다. 112 줄의 코드로 RNN 전체 과정을 구현하였습니다.
vocabulary를 만들고, truncated back propagation 을 수행하는 모델을 구현한 코드입니다.
그리고 실제 Model을 학습시키고 샘플링도 할 수 있습니다.
RNN을 구성하는 것이 엄청나게 어려워 보일 수 있지만 사실은 그렇지 않습니다.
슬라이드만 보면 잘 모르실 수 있습니다. 여러분이 직접 파일을 열어서 코드를 한줄 씩 살펴보시기 바랍니다.
Numpy로만 작성된 dependencies가 없는 코드입니다. 코드를 읽기에도 비교적 쉽습니다.
RNN Language model 로 아주 재미있는 것들을 학습시킬 수 있습니다.
RNN으로 어떤 문장이건 학습시킬 수 있습니다. 인터넷에서 아무 문장이나 긁어와서 학습시킬 수 있습니다.
가령 셰익스피어의 작품들을 RNN으로 학습시켜 볼 수 있습니다.
학습 초기에는 모델이 의미없는 문장들만 뱉어냅니다. 하지만 학습을 시키면 시킬수록 의미있는 문장을 만들어냅니다.
학습이 잘 끝나면 상당히 셰익스피어 풍의 문장들을 만들어냅니다.
"Why do what that day... replied" 어쩄든 상당히 셰익스피어의 문장 처럼 보입니다.
더 학습을 많이 시키면 훨씬 더 긴 문장들도 만들어낼 수 있습니다.
RNN을 이용하면 이런 셰익스피어 풍의 문장과 같은 여러가지 신기한 것들을 학습시킬 수 있습니다.
모델이 HEAD에 발화자를 넣어야한다는 것을 압니다. (예 : "VIOLA:")
그리고 바로 밑에 셰익스피어풍의 문장들을 만들어냅니다.
다른 문장을 시작할 때 한 줄을 비워야 하는 것도 압니다.
이건 엄청난 것입니다. 문장의 구조를 아주 완벽하게 학습했습니다.
훨씬 더 엄청난 것도 있습니다. 인터넷에서 찾았는데요, 혹시 여기 수학 전공자가 있나요?
"algebraic topology" 수업을 들어본 분이 계신가요? 몇 분정도 계시는군요
여러분이 저보다 "algebraic topology"를 더 잘 하시겠네요. 제가 얼마전에 온라인"algebraic topology" 교과서를 찾았습니다.
이 교과서 파일은 수학적인 내용으로 가득 차 있습니다.
그리고 수식이 LaTex 문법으로 작성되어 있습니다. LaTex을 쓰면 수식을 코드로 작성할 수 있습니다.
그러면 algebraic topology 교과서의 LaTex 코드를 우리가 만든 RNN Language Model로 학습시킬 수 있습니다.
자 이걸 학습시키게 되면 (웃음) 이런 식으로 algebraic topology스러운 문장들을 만들어낼 수 있습니다.
모델이 수식도 만들어 냅니다.
"To prrov study that F_sub U is a covering of x prime.. blah blah" (왼쪽 4번째 문단)
unions도 만들어내고, proofs의 끝에 사각형도 만들어냅니다.
lemmas도 만들어내고 이전 lemmas를 참조하기도 합니다.
bi-lemma question 라던지 R 같은 기하학적인 내용도 모두 만들어냅니다. 엄청 대단하죠
diagrams을 만들어내려고도 합니다.
commutative diagram은 algebraic topology에서 아주 많이 사용됩니다.
모델이 이 다이어그램을 열심히 만들어 내려 했지만 물론 이 다이어그램은 아무 의미가 없습니다.
그리고 또 재미있는 점 중 하나는 모델이 "증명 생략" 도 학습합니다.
가끔 이런 경우가 있죠. "theorem : blah blah blah, proof : 생략"
교과서에서 증명이 생각되는 부분도 모델이 정확하게 학습한 것입니다.
또 다른 재미있는 것들도 할 수 있습니다. 이번에는 Linux Kernel의 전체 소스코드를 학습시켰습니다.
코드를 character level로 학습시켰습니다.
학습된 모델에서 샘플링을 해보면 C 소스코드 스러운 것들이 나옵니다.
모델이 if 문 작성법을 알고 있습니다. 코드 짜는 스킬이 어마어마 합니다.
들여쓰기와 중괄호를 쓰는법도 잘 알고있습니다.
주석다는 법도 알고있습니다. 물론 뜻은 아무 의미도 없습니다.
이 모델의 문제점 중 하나는. 변수를 선언해 놓고 쓰지를 않다는 것입니다.
반대로 선언하지도 않은 변수를 쓰기도 합니다. 이 코드는 컴파일되지 않습니다.
이 코드를 Linux에 pull request 하고싶진 않네요
이 모델은 GNU license를 추가하는 법도 압니다.
GNU license 다음에 include 가 나오고 include 가 몇 번 나오고 소스코드가 나옵니다.
이 모델은 데이터의 일반적인 구조를 아주 잘 학습했습니다.
다시 한번 말씀드립니다만, 우리가 모델에게 요청한 것은 그저 시퀀스의 다음 문자를 예측하라는 것이였습니다.
구조에 대해서는 전혀 말해주지 않았죠
하지만 모델은 학습과정 동안에 시퀀스 데이터의 숨겨진 구조(latent structure)를 알아서 학습합니다.
결국 알아서 코드를 작성하게 된 것입니다. 아주 대단합니다.
저와 Andrej가 몇 년전에 낸 논문이 있습니다. 학습한 모델이 도대체 어떤 방식으로 동작하는지 알아내고 싶었습니다.
RNN에는 hidden vector가 있고 이 vector가 계속 업데이트됩니다.
우리는 그 Vector를 추출해보면 해석 가능한 의미있는 것들이 나올수도 있지 않을까 추측해 보았습니다.
그래서 우리는 RNN language model을 특정 dataset으로 학습시키고,
그리고 hidden vector를 하나 뽑아서 어떤 값들이 들어있는지 살펴보기로 했습니다.
이 서로 다른 hidden states가 도대체 어떤 것들을 예의주시하는지 알아보기 위해서였죠
이 실험을 해보면, 대부분의 hidden state는 아무 의미 없는 패턴으로 예의 주시하고 있습니다.
여기서 우리가 한 일은 vector 하나를 뽑은 다음에 이 시퀀스를 다시 한번 forward 시켜 보는 것입니다.
여기에서 각 색깔은, 시퀀스를 읽는 동안에 앞서 뽑은 hidden vector의 값을 의미합니다.
RNN의 대부분의 Cell은 해석하기 어렵습니다.
대부분은 다음에 어떤 문자가 와야할 지 알아내기 위한 low level language modeling 정도로밖에 보이지 않습니다.
하지만 일부는 해석해볼만 합니다.
그러다가 따옴표(quotes)를 찾는 벡터를 알아냈습니다.
이 vector가 하는 일을 살펴보면 처음에는 계속 off off off off ... 입니다. 파란색이죠. (파란색이 off)
그러다가 따옴표를 만나면 값이 켜집니다(빨간색) 그리고 따옴표가 닫히기 전까지 유지됩니다.
그러다가 두 번째 따옴표를 만나면 다시 값이 꺼집니다.
이런 식으로, 그저 우리는 모델이 다음 문자를 예측하도록 학습시켰을 뿐이지만 모델은 더 유용한 것들을 학습하는 것입니다.
그런 유용한 것들을 학습하기 위해서 그 Cell이 따옴표를 감지할 수 있게 된 것입니다.
우리는 또, 줄 바꿈을 위해서 현재 줄의 단어 갯수를 세는 듯해 보이는 Cell도 발견했습니다.
처음에는 0으로 시작했다가. 줄이 점점 길어지면 점점 빨간색으로 변합니다.
점점 증가하다가 줄바꿈이 이루어지면 다시 0으로 리셋됩니다.
이 Cell은 언제 모델이 new line characters을 필요로 할 지 지속적으로 추적하는 역할을 한다고 볼 수 있습니다.
그리고 우리는 linux 코드를 학습시킬 때 발견한 것도 있습니다.
우리는 if 문의 조건부에서 값이 켜지는 Cell을 발견했습니다. 이 Cell은 조건부의 내부와 외부를 구별할 수 있습니다.
이를 통해 모델이 시퀀스를 더 잘 학습할 수 있도록 도와줍니다.
그 밖에도 Comments를 찾아내거나 혹은 들여쓰기 레벨을 세는 듯한 Cell도 발견 했습니다.
정말 놀라운 일입니다. 우리는 그저 다음 문자를 예측하는 모델을 학습시켰을 뿐인데
결국 모델은 입력 데이터의 구조를 학습하게 되었기 때문입니다.
우리는 Computer Vision 수업이니 다시 Computer Vision 에 관련된 예시로 돌아가 보겠습니다.
앞서 Image Captioning Model에 대해서 몇 번 언급했었습니다.
이 모델은 입력은 이미지이고 출력은 자연어로 된 Caption 입니다.
이 문제를 다루는 몇몇 논문들이 있습니다. 다들 접근 방법은 비슷합니다.
이 그림은 그 논문들 중 저희 연구실에서 나온 논문입니다. 아주 "공정한 기준으로?" 예시를 이 논문으로 선택헀습니다.
우선 Caption은 가변길이 입니다. Caption 마다 다양한 시퀀스 길이를 가지고 있습니다.
여기에 RNN Language Model가 아주 잘 어울립니다.
모델에는 입력 이미지를 받기 위핸 CNN이 있습니다. CNN은 지금까지 아주 많이 살펴봤었죠
CNN은 요약된 이미지정보가 들어있는 Vector를 출력합니다. 이 Vector는 RNN의 초기 Step의 입력으로 들어갑니다.
그러면 RNN은 Caption에 사용할 문자들을 하나씩 만들어냅니다.
그렇다면 이 모델을 학습시킨 후에 Test time에 어떻게 동작하는지 알아봅시다.
지금까지 살펴봤던 character level languate model과 아주 유사합니다.
우선 입력 이미지를 받아서 CNN의 입력으로 넣습니다. 다만 softmax scores를 사용하지 않고
직전의 4,096-dim vector를 출력으로 합니다.
이 vector를 이용해서 전체 이미지 정보를 요약하는데 사용할 것입니다.
앞서 RNN language models에서 배웠듯이 모델이 문장을 생성해 내기에 앞서 초기 값을 넣어줘야 합니다.
이 경우에는 입력이 특별합니다. 모델에게 "여기 이미지 정보가 있으니 이 조건에 맞는 문장을 만들어줘!" 라고 시작해야합니다.
이전 까지의 모델에서는 RNN 모델이 두 개의 가중치 행렬을 입력으로 받았습니다. 하나는 현재 스텝의 입력이고
다른 하나는 이전 스텝의 Hidden state 이었죠. 그리고 이 둘을 조합해서 다음 hidden state를 얻었습니다.
하지만 이제는 이미지 정보도 더해줘야 합니다.
사람마다 모델에 이미지정보를 추가하는 방법이 다르겠지만 가장 쉬운 방법은 세 번째 가중치 행렬을 추가하는 것입니다.
다음 hidden state를 계산할 때마다 모든 스텝에 이 이미지 정보를 추가합니다.
자 이제는 vocabulary의 모든 스코어들에 대한 분포를 계산할 차례입니다.
이 문제에서 vocabulary는 "모든 영어 단어들" 과 같이 엄청나게 큽니다.
그 분포에서 샘플링을 하고 그 단어를 다음 스텝의 입력으로 다시 넣어줄 것입니다.
샘플링된 단어(y0)가 들어가면 다시 vacab에 대한 분포를 추정하고 다음 단어를 만들어냅니다.
모든 스텝이 종료되면 결국 한 문장이 만들어집니다.
이 때, 라는 특별한 토큰이 있는데 이는 문장의 끝을 알려줍니다.
가 샘플링되면 모델은 더이상 단어를 생성하지 않으며 이미지에 대한 caption이 완성됩니다.
Train time에는 모든 caption의 종료지점에 토큰을 삽입합니다.
네트워크가 학습하는 동안에 시퀀스의 끝에 토큰을 넣어야 한다는 것을 알려줘야 하기 때문입니다.
학습이 끝나고 Test time에는 모델이 문장 생성을 끝마치면 토큰을 샘플링합니다.
이 모델은 완전히 supervised learning으로 학습시킵니다.
따라서 이 모델을 학습시키기 위해서는 natural language caption이 있는 이미지를 가지고 있어야 합니다.
이 Task를 위한 가장 큰 데이터셋은 아마 Microsoft COCO 데이터셋이 아닐까 싶습니다.
이 모델을 학습시키기 위해서는 natural language model과 CNN을 동시에 backp 시킬 수 있습니다.
이 모델을 학습시키고 나면 상당히 그럴듯한 결과를 보입니다.
지금 보이는 것들이 실제 모델의 결과입니다.
고양이가 여행용 가방에 앉아있습니다. "A cat sitting on a suitcase on the floor"
상당히 인상적인 결과입니다.
고양이가 나뭇가지에 앉아있습니다. "A cat is sitting on a tree branch"
이 또한 상당히 놀랍습니다.
두 사람이 서핑보드를 들고 해변을 걷고있습니다. "Two people walking on the beach with surfbards"
이 모델은 상당히 파워풀하고 이미지를 묘사하기 위해 비교적 복잡한 captions도 만들어낼 수 있습니다.
하지만 그렇긴해도 모델이 아주 완벽하진 않습니다.
전부다 마법같은 일만 일어나는 것은 아닙니다. 이 모델도 다른 Machine learning 모델들 처럼
Train time에 보지 못한 데이터에 대해서는 엄청 잘 동작하지는 않습니다.
가령, 여자가 손에 고양이를 들고 있습니다. "A woman is holding a cat in her hand"
하지만 이미지에 고양이는 없습니다.
하지만 여자가 모피 코트를 입고있습니다. 아마도 모델이 모피 코트의 텍스쳐를 고양이로 보고 있는 것 같습니다.
여자가 해변에서 서핑보드를 들고있습니다. "A Woman standing on a beach holding a surfboard"
하지만 분명 이 사람은 서핑보드를 들고있지 않습니다. 물구나무서기를 하고 있죠
모델이 물구나무서기를 하고있다는 사실을 놓쳤습니다.
그리고 여기 나뭇가지에 쳐있는 거미줄 사진이 있습니다.
하지만 모델은 나뭇가지에 새가 앉아있다고 생각했습니다. "A bird is perched on a tree branch"
모델은 거미에 관한 것들을 완전히 놓쳤습니다. 하지만 이 모델은 Train time에 거미를 보지 못했습니다.
Train time에는 새가 나뭇가지에 않는다는 사실만 배웠을 뿐입니다.
따라서 납득이 가는 실수하고 볼 수 있습니다.
그리고 여기 밑에 보시면 모델은 이 사람이 공을 던지는 중인지 받는 중인지 구분하지 못합니다.
하지만 어찌됐든 야구선수와 야구공이 어떤 연관이 있음은 모델이 알고 있습니다.
다시한번 말씀드리지만 이 모델은 완벽하지 않습니다.
Train data와 유사한 이미지를 던져주면 꾀나 잘 동작합니다.
하지만 그 이상 일반적인 문제를 풀기는 조금 어렵습니다.
조금 더 진보된 모델이 있습니다. Attention 이라는 모델입니다.
이 모델은 Caption을 생성할 때 이미지의 다양한 부분을 집중해서(attention) 볼 수 있습니다.
이번 시간에는 Attention 모델을 깊게 다루지는 않겠습니다.
어떻게 동작하는지 간단하게 말씀드리자면 우선 CNN이 있습니다.
CNN로 벡터 하나를 만드는게 아니라 각 벡터가 공간정보를 가지고 있는 grid of vector를 만들어냅니다.(LxD)
Forward pass시에 매 스텝 vocabulary에서 샘플링을 할 때
모델이 이미지에서 보고싶은 위치에 대한 분포 또한 만들어냅니다.
이미지의 각 위치에 대한 분포는 Train time에 모델이 어느 위치를 봐야하는지에 대한 attention이라 할 수 있습니다.
첫 번째 hidden state(h0)는 이미지의 위치에 대한 분포를 계산합니다.
이 분포(a1)를 다시 벡터 집합(LxD Feature)과 연산하여 이미지 attention(z1)을 생성합니다.
이 요약된 벡터(z1)는 Neural network의 다음 스텝의 입력으로 들어갑니다.
그리고 두 개의 출력이 생성됩니다. (a2, d1)
하나는 vocabulary의 각 단어들의 분포입니다(d1). 그리고 다른 하나(a2)는 이미지 위치에 대한 분포입니다.
이 과정을 반복하면 매 스텝마다 값 두개(a, d)가 계속 만들어집니다.
Train을 끝마치면, 모델이 caption을 생성하기 위해서 이미지의 attention을 이동시키는 모습을 볼 수 있습니다.
가령 여기 만들어진 caption은 "A bird flying over a body of water." 입니다.
caption을 만들 때 마다 이미지 내에 다양한 곳들에 attention을 주는 것을 볼 수 있습니다.
사실 여기에는 hard/soft attention의 개념이 있습니다만, 너무 깊게 들어가진 않겠습니다.
soft attention의 경우에는 "모든 특징"과 "모든 이미지 위치"간의 weighted combination을 취하는 경우입니다.
반면 hard attention의 경우에는 모델이 각 타임 스텝마다 단 한곳만 보도록 강제한 경우입니다.
hard attention의 경우에 이미지 위치를 딱 하나만 정해야 하는데, 사실상 하나만 정하기 까다롭습니다.
따라서 Hard attention을 학습시키려면 기본 backprob 보다는 조금 더 fanier한 방법을 써야만 합니다.
이에 관련된 것들은 다음에 reinforcement learning 시간에 더 다루겠습니다.
Attention Model을 학습시키고 나서 Caption을 생성해보면
실제로 모델이 Caption을 생성할 때 의미있는 부분에 attention을 집중한다는 것을 알 수 있습니다.
여자가 공원에서 원반을 던지고 있습니다. 에서 "A woman is throwing a frisbee in a park"
Attention mask를 살펴보면. 모델이 "원반(frisbee)" 라는 단어를 생성할 때
이미지에서도 실제 원반이 위치하는 곳을 정확하게 attention하는 것을 알 수 있습니다.
엄청 대단합니다. 우리는 모델에게 매 스텝 어디를 보라고 말해준 적이 없습니다.
모델 스스로가 Train time에 알아냈습니다.
모델이 그쪽(원반) 영역에 집중하는 것이 올바른 일이라는 것을 스스로 알아낸 것입니다.
모델 전체가 미분가능하기 때문에
soft attention 또한 backprob이 가능합니다. 따라서 이 모든 것들은 train time에서 나온 것들입니다.
아주 대단합니다.
RNN + Attention 조합은 Image captioning 뿐만 아니라 더 다양한 것들을 할 수 있습니다.
가령 Visual Question Answering(VQA) 같이 말이죠.
이 문제에서는 입력이 두 가지 입니다. 하나는 이미지이고 다른 하나는 이미지에 관련된 질문입니다.
왼쪽과 같은 이미지에 다음과 같은 질문을 할 수 있을 것입니다. Q: 트럭에 그려져 있는 멸종위기 동물은 무엇입니까?
모델은 네개의 보기 중에서 정답을 맞춰야 합니다.
이 모델 또한 RNN과 CNN으로 만들 수 있습니다.
이 경우에는 "many to one" 의 경우입니다.
모델은 자연어 문장(질문)을 입력으로 받아야 합니다.
이는 RNN을 통해 구현할 수 있습니다. RNN이 질문을 vector로 요약합니다.
그리고 이미지 요약을 위해서는 CNN이 필요합니다.
CNN/RNN에서 나온 벡터를 조합하면 질문에 대한 분포를 예측할 수 있을 것입니다.
그리고 간혹 VQA 문제를 풀기 위해서 soft special attenion 알고리즘을 적용하는 경우도 있습니다.
이 예시를 보시면 모델이 정답을 결정하기 위해서 이미지에 대한 attention을 만들어내는 것을 볼 수 있습니다.
질문있나요?
질문은 "어떻게 서로 다른 입력을 조합하는지" 입니다. (CNN output과 RNN output을 어떻게 합치는지)
어떻게 요약된(encoded) 질문 벡터와, 요약된 이미지 벡터를 조합하는지를 여쭤보시는 것인가요?
질문은 "encoded image와 encoded question를 어떻게 조합할 수 있는지" 입니다.
가장 쉬운 방법중 하나는 concat으로 붙혀서 FC-Layer의 입력으로 만드는 방법입니다.
이 방법이 가장 흔한 방법이고. 가장 먼저 시도해볼 수 있는 방법입니다.
하지만 간혹 사람들이 더 강력한 함수를 만들기 위해서 두 벤터간의 더 복잡한 조합을 만들어내는 경우도 있습니다.
어찌됐든 Concat하는 방법도 맨 처음 시도해보기에는 나쁘지 않은 방법입니다.
지금까지 RNN을 활용한 다양한 예제들을 살펴보았습니다. 이 방법들 모두 대단한 방법들입니다.
왜냐하면 RNN을 이용하면 CV와 NLP 문제를 조합시키는 복잡한 문제들을 풀 수 있기 때문입니다.
이 복잡한 과정들은 레고 블럭들을 쌓는 것으로 볼 수 있습니다.
가령 Image Captiong이나 VQA 같은 모델들은 여러 모듈(RNN,CNN)을 비교적 단순한 방법으로도 구현할 수 있습니다.
또 한 가지 말씀드리고 싶은 것은, 지금까지는 단일 RNN 레이어를 사용했습니다. hidden state가 하나 뿐이었습니다.
하지만 여러분이 자주 보게될 모델들은 Multi-layer RNN입니다.
3-Layer RNN이 있습니다. 입력이 첫 번째 RNN으로 들어가서 첫 번째 hidden state를 만들어냅니다.
RNN 하나를 돌리면 hidden states 스퀀스가 생깁니다. (밑에서 두 번째 행)
이렇게 만들어진 hidden state 시퀀스를 다른 RNN의 입력으로 넣어줄 수 있습니다.
그러면 두 번째 RNN layer가 만들어내는 또 다른 hidden states 시퀀스가 생겨납니다. (밑에서 세 번째)
이런 식으로 RNN layer를 쌓아올릴 수 있을 것입니다.
이렇게 하는 이유는 모델이 깊어질수록 다양한 문제들에서 성능이 더 좋아지기 때문입니다.
이 법칙(더 깊게 쌓는 방법)이 RNN에서도 적용됩니다. 많은 경우에 3~4 layer RNN을 사용합니다.
하지만 보통은 엄청나게 싶은 RNN모델을 사용하지는 않습니다.
일반적으로는 2,3,4 layer RNN이 적절합니다.
RNN을 사용할 때 문제점이 있습니다. 이는 아주 흥미롭고 중요한 주제입니다.
RNN을 학습시킬 때 어떤 일이 생기는지 아주 신중히 생각해 봐야 합니다.
여기 지금까지 우리가 봐왔던 일반적인(vanilla) RNN Cell이 있습니다.
입력은 "현재 입력, x_t" 와 "이전 hidden state h_t-1" 입니다. 그리고 이 두 입력을 쌓습니다(stack).
이렇게 두 입력을 쌓고 가중치 행렬 W와 행렬 곱 연산을 하고 tanh 를 씌워서 다음 hidden state(h_t)를 만듭니다.
Vanilla RNN의 기본 수식입니다.
그러면 이 아키텍쳐는 backward pass에 그레디언트를 계산하는 과정에서 어떤 일이 발생할까요?
우선 Backward pass 시 h_t에 대한 loss의 미분값을 얻습니다.
그 다음 Loss에 대한 h_t-1의 미분값을 계산하게 됩니다.
backward pass의 전체과정은 여기 보이시는 빨간색 통로를 따르게 됩니다.
우선 그레이언트가 tanh gate를 타고 흘러갑니다. 그 다음 "Mat mul gate" 를 통과합니다.
여러분이 과제로 구현해 보았듯이 Mat mul gate의 backprop은
결국 이 transpose(가중치 행렬) 을 곱하게 됩니다.
이는 매번 vanilla RNN cells을 하나 통과할 때 마다 가중치 행렬의 일부를 곱하게 된다는 것을 의미합니다.
RNN의 특성 상 RNN이 여러 시퀀스의 Cell을 쌓아 올리는 사실을 고려하면
그레디언트가 RNN 모델의 Layers 시퀀스를 통해 어떤 방식으로 전달되는지 생각해 볼 수 있습니다.
수상한 낌새가 보이기 시작합니다.
가령 우리가 h_0에 대한 그레이언트를 구하고자 한다면 결국에는 모든 RNN Cells을 거쳐야 합니다.
cell 하나를 통과할 때 마다 각 Cell의 행렬 W transpose factors가 관여합니다.
다시 말해 h_0 의 그레디언트를 계산하는 식을 써보면 아주 많은 가중치 행렬들이 개입하며, 이는 안좋습니다.
우선 가중치를 행렬이라고 생각하지 말고 스칼라로 생각해봅시다.
우리이게 스칼라 값들이 있고 이 값들을 계속해서 곱한다고 했을 때
여기 예제처럼 4개의 예제 뿐만 아니라 수백 개의 스텝이 있는 경우라면
값들을 수백 번 곱해줘야 합니다. 아주 안좋습니다.
만약 곱해지는 값이 1보다 큰 경우라면 점점 값이 커질 것이고 1보다 작은 경우라면 점점 작아져서 0이 될 것입니다.
이 두 상황이 일어나지 않으려면 곱해지는 값이 1인 경우밖에 없습니다.
실제로 1이 되기는 상당히 드뭅니다.
스칼라에서의 이 intuition은 행렬에서도 동일하게 적용됩니다.
가령 행렬의 특이값(singular value)이 엄청나게 큰 경우를 생각해 볼 수 있습니다.
singular value가 엄청 큰 행렬을 계속 곱하는 경우에도 역시 h_0의 그레디언트는 아주 커지게됩니다.
이를 "exploding gradient problem" 라고 합니다.
backprop시 레이어가 깊어질수록 그레디언트가 기하급수적으로 증가하는 현상입니다.
행렬의 특이값이 1보다 작은 경우라면 정 반대의 현상이 발생합니다. 이제는 기하급수적으로 그레디언트가 작아집니다.
이를 "vanishing gradient problem" 이라고 합니다.
그래서 사람들은 "gradient clipping" 이라는 기법을 사용하곤 합니다.
"gradient clipping" 은 휴리스틱한 기법중 하나입니다. 그레디언트를 계산하고
그레디언트의 L2 norm이 임계값보다 큰 경우 그레디언트가 최대 임계값을 넘지 못하도록 조정해줍니다.
이 방법은 그닥 좋은 방법은 아니지만, 실제로는 많은 사람들이 RNN 학습에 이 방법을 활용합니다.
exploding gradient problem을 해결하기에는 비교적 유용한 방법이긴 합니다.
하지만 vanishing gradient problem를 다루려면 조금더 복잡한 RNN 아키텍쳐가 필요합니다.
이는 LSTM에 관한 것입니다. LSTM은 Long Short Term Memory라는 뜻입니다.
LSTM은 RNN의 fancier 버전입니다.
LSTM은 vanishing & exploding gradients 문제를 완화시키기 위해서 디자인되었습니다.
"gradient clipping" 같은 hack 을 쓰지 말고, 그레디언트가 잘 전달되도록 아키텍쳐 자체를 디자인한 경우입니다.
기존에 배웠던 fancier CNN 아키텍쳐들과 유사한 느낌입니다.
사실 LSTM은 1997년도에 나왔습니다.
LSTM 이라는 아이디어 자체를 꽤 오랫동안 존재했습니다.
사람들은 90년대에 이미 LSTM을 연구하고 있었고. 시대를 앞서갔던 연구라고 할 수 있습니다.
20년이 지난 오늘날 LSTM은 어디서나 사용됩니다.
LSTM은 아주 재밌게 생겼습니다.
vanilla RNN은 hidden state가 있었습니다. 그리고 매 스텝 재귀적인 방법으로 hidden state를 업데이트했습니다.
LSTM에는 한 Cell 당 두 개의 Hidden state가 있습니다.
하나는 h_t 입니다. vanilla RNN에 있었던 hidden state(h_t)와 유사한 개념입니다.
하지만 LSTM의 경우 "Cell state" 인 c_t라는 두 번째 벡터가 있습니다.
Cell state, c_t 는 LSTM 내부에만 존재하며 밖에 노출되지 않는 변수입니다.
LSTM의 Updata 식을 살펴봅시다.
LSTM도 두 개의 입력을 받습니다.(h_t-1, x_t)
그리고 4개의 gates를 계산합니다. i, f, o, 그리고 g 입니다.
이 gates를 cell states, c_t를 업데이트하는데 이용합니다. 그리고 c_t로 다음 스텝의 hidden state를 업데이트합니다.
LSTM는 아주 흥미롭게 생겼습니다. 앞으로 몇 장의 슬라이드는 LSTM이 어떻게, 왜 동작하는지 살펴보겠습니다.
vanishing or exploding gradients의 관점에서 말이죠.
우선 LSTM에서는 이전 hidden state인 h_t와 현재의 입력인 x_t를 입력으로 받습니다.
vanilla RNN와 동일합니다.
vanilla RNN의 경우에 두 입력(h_t-1, x_t)를 Cancat하고 행렬곱 연산으로 hidden state를 직접 구했습니다.
LSTM의 경우는 조금 다릅니다. 이전 hidden state와 입력을 받아서 쌓아 놓습니다.
그리고 네 개의 gates의 값을 계산하기 위한 커다한 가중치 행렬을 곱해줍니다.
각 gates 출력은 hidden state의 크기와 동일합니다.
물론 간혹 각 gate의 가중치 행렬의 크기를 다양한 방법으로 디자인할 수도 있습니다.
어떤 사람들은 모든 값들을 조합해서 하나의 큰 가중치 행렬로 만들기도 합니다.
하지만 여러 방법의 기본 아이디어는 모두 같습니다.
기본적으로는, h_t-1과 x_t를 입력으로 받고 gates 4개를 계산해야 합니다.
gates 4개는 [i, f, o, g]인데. 기억하기 쉽게 "ifog" 라고 부르기도 합니다.
I 는 input gate입니다. I는 Cell에서의 입력 x_t에 대한 가중치입니다.
F는 forget gate입니다. F는 이전 스텝의 Cell의 정보를 얼마가 망강(forget) 할지에 대한 가중치입니다.
O는 Output gate입니다. O는 Cell state, c_t를 얼마나 밖에 드러내 보일지에 대한 가중치입니다.
G는 그닥 좋은 이름은 아니지만 저는 "gate gate" 라고 부릅니다.
G는 input cell을 얼마나 포함시킬지 결정하는 가중치입니다.
중요한 점 중 하나는, 각 gate에서 사용하는 nin-linearity가 각양각색 이라는 점입니다.
input/forget/output gate의 경우는 sigmoid를 샤용합니다.
gate의 값이 0~1 사이라는 의미입니다.
반면 gate gate는 tanh를 사용합니다. 따라서 gate gate는 -1 ~ +1 의 값을 갖습니다.
이 부분이 조금 이상해 보일 수도 있지만, 사실은 더 이치에 맞습니다. 가령 gate값이 binary라고 생각해 봅시다.
값이 binary(0,1 or -1,+1) 이라면 어떤 일이 일어날까요?
밑에 수식을 살펴봅시다.
이전 스텝의 Cell states(C_t-1)는 forget gate와 element-wise multiplication 합니다.
결과 vector는 (f*c_t-1) 0또는 1일 것입니다.
따라서 forget gate = 0인 element는 이전 cell state를 잊습니다.
반면 forget gate = 1이면 cell state의 element를 계속 기억합니다.
지금까지 살펴본 forget gate는 이전 cell state의 gate on/off 를 결정했습니다.
이제 두 번째 수식을 살펴보겠습니다. element-wise product인 i * g 입니다.
벡터 i의 경우에는 시그모이드에서 나온 녀석이므로 0 또는 1입니다.
cell state의 각 element에 대해서, 이 cell state를 사용하고 싶으면 1 이 됩니다.
반면 쓰고싶지 않으면 i = 0 이 될 것입니다.
gate gate는 tanh 출력이기 때문에 값이 -1 또는 +1 입니다.
c_t 는 현재 스텝에서 사용될 수 있는 "후보" 라고 할 수 있습니다.
Cell State(c_t)를 계산하는 전체 수식을 살펴봅시다.이 수식은 두 개의 독립적인 scaler 값(f, i)에 의해 조정됩니다.
각 값(f, i)은 1까지 증가하거나 감소합니다.
c_t의 수식을 해석해보면, 우선 이전 cell state(c_t-1)을 계속 기억할지 말지를 결정합니다. (f * c_t-1)
그런다음 각 스텝마다 1까지 cell state의 각 요소를 증가시키거나 감소시킬 수 있습니다. (i * g)
즉 cell state의 각 요소는 scaler integer counters 처럼 값이 줄었다 늘었다 하는 것으로 볼 수 있습니다.
Cell state를 계산했다면 이제는 hidden state를 업데이트 할 차례입니다. h_t는 실제 밖으로 보여지는 값입니다.
그렇게 때문에 cell state는 counters의 개념으로 해석할 수 있습니다. 각 스텝마다 최대 1 또는 -1씩 세는 것이죠
그리고 이 값은 tanh를 통과합니다. 그리고 최종적으로 output gate와 곱해집니다.
그리고 output gate 또한 sigmoid에서 나온 값입니다. 따라서 0 ~ 1의 값을 가집니다.
output gate는 각 스텝에서 다음 hidden sate를 계산할 때 cell state를 얼마나 노출시킬지를 결정합니다.
대부분의 사람들이 자기들만 알아볼 수 있는 복잡한 LSTM 다이어그램을 그려놓고 남들에게 설명하려는 경향이 있습니다.
그 중 이 다이어그램은 제가 만들었습니다. :D
이 다이어그램을 보시면 LSTM cell이 어떤게 동작하는지 알 수 있습니다.
우선 왼쪽을 보면 이전의 cell state(c_t-1)과 hidden state(h_t-1) 을 입력으로 받습니다. 현재 입력 x_t도 있죠
우선 이전 hidden state (h_t-1)과 현재 입력 x_t를 쌓습니다.
그리고 가중치 행렬 W를 곱해서 4 개의 gates를 만듭니다.
Non-Linearity에 관해서는 이전 슬라이드에서 다뤘으므로 여기에서는 제외시켰습니다.
그리고 forget gate를 이전 cell state(c_t-1)와 곱합니다.
그리고 input/gate gate가 element wise로 곱한 후 cell state(c_t-1 *f)와 곱해서 다음 cell 을 만듭니다.
c_t는 tanh를 거친 후 output gate와 곱해져서 다음 hidden state(h_t)를 만들어냅니다.
질문있나요?
(질문 내용 X) 아닙니다. 각 gate는 각 gate마다 곱해지는 가중치 행렬을 가지고 있습니다.
우선 x와 h를 쌓으면 전체 h x 1 행렬이 됩니다.
그리고 가중치 행렬의 크기는 4h x 2h 입니다.
이 가중치 행렬은 행렬 4개를 합쳐 놓은 것이라고 보시면 됩니다. 각 4개의 행렬은 서로 가능 gate를 계산합니다.
간혹 수식를 더 간단하게 쓰기 위해서 4개의 행렬을 그저 행렬 W로 표현하는 경우도 있습니다.
가중치 행렬이 합쳐있어 보이긴 해도 결국은 4개의 가중치 행렬로 나누어져 있다고 보시면 됩니다.
하지만 결국은 모두 두 개의 입력(x, h) 를 쌓고 행렬 곱 연산을 수행하는 것입니다.
슬라이드의 그림을 살펴보겠습니다. LSTM의 backward pass는 어떨까요?
앞서 vanilla RNN의 경우에는 backward pass에서 문제점이 있었습니다. 가중치 행렬 w가 계속해서 곱해지는 문제였죠.
하지만 LSTM에서는 상황이 많이 달라졌습니다.
LSTM에서 cell state의 gradient를 계산하는 backward 경로를 살펴보게 되면, 아주 괜찮아보입니다.
자 그럼 cell state에서 내려오는 upsteam gradient를 살펴봅시다.
우선 "addition operation"의 backprob이 있습니다.
지난 강의에서 배웠듯이 "addition" 에서는 upstream gradient가 그저 두 갈래로 복사됩니다.
따라서 "element wise multply" 로 직접 전달됩니다.
따라서 그레디언트는 upsteam gradient와 forget gate의 element wise 곱입니다.
결국 Cell state의 backprob은 그저 upstream gradient * forget gate 입니다.
이 특성은 vanilla RNN에 비해 좋은점이 두 가지 있습니다.
우선 forget gate와 곱해지는 연산이 matrix multiplication가 아닌 element-wise라는 점입니다.
full matrix multiplication 보다는 element wise multiplication이 더 낫습니다.
두 번째는 element wise multiplication을 통해 매 스텝 다른 값의 forget gate와 곱해질 수 있다는 점입니다.
앞서 vanilla RNN의 경우에는 동일한 가중치 행렬(h_t)만을 계속 곱했습니다.
이는 exploding/vanishing gradient문제를 일으켰습니다.
반면 LSTM에서는 forget gate가 스텝마다 계속 변합니다.
따라서 LSTM은 exploding/vanishing gradient 문제를 더 쉽게 해결할 수 있습니다.
그리고 forget gate는 sigmoid에서 나온 값이므로 element wise multply가 0~1 사이의 값입니다.
따라서 forget gate를 반복적으로 곱한다고 했을 때 더 좋은 수치적 특성을 보일 수 있습니다.
그리고 또 한가지 명심해야 할 점은, vanilla RNN의 backward pass에서는 매 스탭 그래디언트가 tanh를 거쳐야 했습니다.
LSTM에서도 hidden state h_t를 출력 y_t를 계산하는 데 사용합니다.
가령 LSTM의 최종 hidden state h_t를 가장 첫 cell state(c_0)까지 backprob하는 것을 생각해보면
RNN처럼 매 스탭마다 tanh를 거치는 것이 아니라 tamh를 단 한번만 거치면 됩니다.
LSTM을 전체적인 모습을 그려보면, Cell state를 통한 backprob은 그레디언트를 위한 고속도로라고 볼 수 있습니다.
그레디언트가 모델의 종단인 Loss에서 가장 처음 Cell State(C_0)까지 흘러가면서 방해를 덜받는 것이죠
질문있나요?
질문은 "궁극적으로 W를 업데이트해야 할텐데, W에 대한 그레디언트는 어떻게 되는지" 입니다.
가중치 W에 대한 Local gradient는 해당 스텝에 해당하는 현재의 cell/Hidden state로부터 전달됩니다.
Vanilla RNN의 경우에는 각 스텝의 가중치 행렬 W들이 서로 영향을 미쳤습니다.
반면 LSTM의 경우에는, 가령 아주 긴 시퀀스가 있고 그레디언트가 맨 끝에서부터 전달되기 시작된다고 했을 때
이 시퀀스의 backprob 과정에서 각 스텝마다 w에 대한 local gradient가 있을 것입니다.
그리고 W의 local gradient는 Cel/Hiddenl state에서 흘러옵니다.
LSTM의 경우 cell state c가 그레디언트를 잘 전달해주기 때문에
w에 대한 local gradient도 훨씬 더 깔끔하게 전달됩니다.
질문 있나요?
질문은 "여전히 Non-linearities가 있으므로 (sigmoid) vanishing gradient 문제에 민감할 수 있는지" 입니다.
그럴지도 모릅니다. 가령 forget gate의 경우 출력이 0~1 이니 항상 1보다 작으므로 그레디언트가 점점 감소할 수 있습니다.
그래서 사람들이 많이 하는 Trick 으로 forget gate의 biases를 양수로 초기화시키는 방법이 있습니다.
이 방법을 이용해서 학습 초기에 forget gate의 값이 1에 가깝도록 해줍니다.
1에 가까운 값이기 때문에 적어도 학습 초기에는 그레디언트의 흐름이 비교적 원활할 것입니다.
그리고 학습이 진행되면 forget gate의 biases가 적절한 자기 자리를 다시 찾아가겠죠
LSTM에서도 vanishing gradient의 위험은 존재합니다. 다만 Vanilla RNN만큼 심하진 않습니다.
덜 위험한 이유 중 하나는 매 스텝 f가 변하기 떄문이고
두 번째 이유는 LSTM에서는 Full Mat-mul이 아닌 element-wise multiplication을 수행하기 때문입니다.
LSTM을 유심히 들여다보면 RsetNet 스럽게 생겼습니다.
ResNet의 Backward pass에서 identity connection이 아주 유용했습니다.
Identity Mapping이 ResNet 그레디언트를 위한 고속도로 역할을 했습니다.
LSTM도 동일한 intuition입니다.
LSTM의 Cell state의 element-wise mult가 그레디언트를 위한 고속도로 역할을 하는 것이죠
유사한 방법으로 "Highway Networks" 라는 논문도 있습니다. LSTM cell과 ResNet의 중간 버전입니다.
사실은 Highway network는 ResNet보다 일찍 나온 논문입니다.
highway network는 모든 레이어에서 "candidate activation"과 "gating function"을 계산합니다.
gating function (g)는 현재 레이어의 이전 입력과 CNN 등에서 나온 candidate activation간의 보간 역할을 해줍니다.
많은 아키텍쳐들(LSTM, ResNet)간의 유사성은
사람들이 아주 깊은 CNN/RNN을 학습시키면서 얻은 영감에서 비롯됩니다. 이 지점에서 많은 교집합이 존재합니다.
다시 말하면 실제로 아주 다양한 RNN 아키텍쳐의 변형된 버전들이 존재합니다.
그 중 LSTM 다음으로 유명한 아키텍쳐는 GRU 입니다. Gated Recurrent Unit 이죠.
업데이트 식은 보시는 바와 같습니다. LSTM과 유사하게 생겼습니다.
Vanishing gradient 문제를 회피하기 위한 element-wise mult gate 등이 보이는군요
그리고 또 "LSTM: A Search Space Odyssey" 라는 논문도 있습니다. 아주 독창적인 제목입니다.
이 논문에서는 LSTM의 수식을 이리저리 바꾸고 실험을 합니다. 가령 non linearities를 바꿔봅니다.
output gate에 꼭 tanh를 써야만 하는지 등을 실험했습니다.
그들은 다양한 질문을 만들고 이에 답할 수 있는 여러가지 실험을 진행하였습니다.
그리고 LSTM 모델을 조금씩 변형시켜보고 어떤 일이 발생하는지 실험하였습니다.
결론은 전부 비슷비슷했다는 것입니다. 어떤 문제에서는 특정 모델이 더 잘 될수는 있겠지만. 결국은 다 비슷했습니다.
하지만 그들이 시도한 어떠한 방법들도 "모든 문제들" 에서 original LSTM보다 엄청나게 좋지는 않았습니다.
이는 LSTM 업데이트 수식이 뭔진 모르겠지만 어쨋든 유용하고. 각자 문제에 적용해볼만하는 것을 시사합니다.
몇 해 전 Google에서도 아주 재미있는 논문이 나왔습니다.
이들은 evolutionary search 기법을 이용해서 아주 많은 임의의 RNN 아키텍쳐를 실험합니다.
이들은 임의로 업데이트 수식을 섞고 addition/multiplication non-linearities를 다양한 조합으로 섞습니다.
Huge Google cluster 를 이용해서 다양한 방법들을 모조리 실험해 버립니다.
하지만 결론은 같습니다. GRU와 LSTM 보다 엄청나게 좋은 모델을 찾아내지는 못했습니다.
조금 변형된 모델이 특정 문제에는 조금 더 좋을수는 있었습니다. 반대로 안 좋을수도 있습니다.
최종 결론으로 아셔야 할 점은 바로 LSTM과 GRU가 아무렇게나 만든 수식이 아니라는 것입니다.
LSTM와 GRU는 Gradient Flow를 아주 적절하게 관리하며 추가된 gate는 아주 유용함은 사실입니다.
오늘 내용을 요약 하자면 RNN은 완전 멋있습니다. RNN으로 다양한 새로운 문제에 도전해 볼 수 있습니다.
떄로는 RNN은 vanishing/exploding gradient 문제에 민감할수도 있습니다.
이 문제들은 weight clipping이나 다른 fancier한 아키텍쳐(LSTM, GRU)로 극복할 수 있었습니다.
그리고 CNN/RNN 아키텍쳐 간에는 교집합이 아주 많았습니다.
다음 시간은 중간고사합니다. 오늘 배운 RNN까지가 범위입니다. 모두 중간고사 화이팅입니다.